/***************************************************************************************** 
*                                     TinyRtos51 
*                                The Real-Time Kernel 
*                              Copyright(c) 2024 fanxsp
*                         SPDX-License-Identifier: APACHE-2.0
*       This software is subject to an open source license and is distributed by fanxsp,
*       pursuant to the terms of the Apache License.
******************************************************************************************/
/***************************************************************************************** 
* 				TinyRtos51 OSMsgQ.c
* Author: fanxsp 
* Revision: 1.00
* Date: 2023-09-16
* 
******************************************************************************************/
#define __IN_OSMSGQ_C
#include "tinyrtos51.h"

#if OSMSGQS > 0

/* MsgQ 控制块 */
OStypeMsgQ OSLOC_MSGQ OSMsgQArea[OSMSGQS] ;

/* API */
/*****************************************************************************************
* 初始化消息队列  在OSStart()前调用
* 参数：eID  消息队列ID   p 队列缓冲区指针 size 队列大小
******************************************************************************************/
void OSInitMsgQ(OStypeInt8u eID,OStypeInt8u OSLOC_MSGQ_BUF *p,OStypeInt8u size) 
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSMSGQS-1) return ;
#endif
	OSMsgQArea[eID].buf = p  ;
	OSMsgQArea[eID].size = size ;
}

/******************************************************************************************
* 等待消息队列  在任务中调用 不能在中断中调用
* 参数：eID  消息队列ID  msg 消息指针,用于接收消息,发生超时则消息指针指向的数据是不可预知的
*       ticks 超时时间，=0 为永久等待
*******************************************************************************************/
#if OSBYTES_OF_DELAYS > 0
void OSWaitMsgQ(OStypeInt8u eID,OStypeInt8u idata *msg,OStypeOfDelays ticks) 
#else
void OSWaitMsgQ(OStypeInt8u eID,OStypeInt8u idata *msg) 	
#endif
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSMSGQS-1) return ;
#endif

	OSEnterCritical() ;
#if OSBYTES_OF_DELAYS > 0
	OSTcbArea[OSTaskRunning].timeout = 0 ;
	while((OSMsgQArea[eID].count == 0)&&(OSTcbArea[OSTaskRunning].timeout == 0))
#else
	while(OSMsgQArea[eID].count == 0)
#endif
	{
		OSTcbArea[OSTaskRunning].state = OSTCB_WAITING ;
#if OSBYTES_OF_DELAYS > 0
		OSTcbArea[OSTaskRunning].delay = ticks ;
		SP++ ;
		*(OStypeOfDelays idata *)SP = ticks ;
#if OSBYTES_OF_DELAYS > 1
		SP++ ;
#endif
#endif
		ACC = (OStypeInt8u)msg ;
		_push_(ACC) ;
		ACC = eID ;
		_push_(ACC) ;
		OSDelFromList(OSTaskRunning) ;
		eID = *(OStypeInt8u idata *)SP ;
		OSAppendToList(OSHeadMsgQ(eID),OSTaskRunning) ;
		OSTaskSw() ;
		_pop_(ACC) ;
		eID = ACC ;
		_pop_(ACC) ;
		msg = (OStypeInt8u idata *)ACC ;
#if OSBYTES_OF_DELAYS > 0
#if OSBYTES_OF_DELAYS > 1
		SP-- ;
#endif
		ticks = *(OStypeOfDelays idata *)SP ;
		SP-- ;
#endif
	}
	
#if OSBYTES_OF_DELAYS > 0
	if(OSTcbArea[OSTaskRunning].timeout == 0)
	{
#endif
		*msg = OSMsgQArea[eID].buf[OSMsgQArea[eID].front] ;
		if(++OSMsgQArea[eID].front == OSMsgQArea[eID].size)  OSMsgQArea[eID].front = 0 ;
		OSMsgQArea[eID].count-- ;
#if OSBYTES_OF_DELAYS > 0
	}
#endif
	OSExitCritical() ;
}

/**********************************************************************************************
* 测试消息队列 消息出列  可以在中断中调用
* 参数：eID  消息队列ID  msg 消息指针
* 返回：0-操作失败  1-操作成功
**********************************************************************************************/
OStypeInt8u OSTryMsgQ(OStypeInt8u eID,OStypeInt8u idata *msg) 
{
	OStypeInt8u tmp ;
	
	tmp = 0 ;
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSMSGQS-1) return tmp ;
#endif
	OSEnterCritical() ;
	if(OSMsgQArea[eID].count != 0)
	{
		tmp = 1 ;
		*msg = OSMsgQArea[eID].buf[OSMsgQArea[eID].front] ;
		if(++OSMsgQArea[eID].front == OSMsgQArea[eID].size) OSMsgQArea[eID].front = 0 ;
		OSMsgQArea[eID].count-- ;
	}
	OSExitCritical() ;
	return tmp ;
}

/**********************************************************************************************
* 读取消息队列 消息不出列  可以在中断中调用
* 参数：eID 消息队列ID  msg 消息指针
* 返回：0-操作失败  1-操作成功
**********************************************************************************************/
OStypeInt8u OSReadMsgQ(OStypeInt8u eID,OStypeInt8u idata *msg) 
{
	OStypeInt8u tmp ;
	
	tmp = 0 ;
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSMSGQS-1) return tmp ;
#endif
	OSEnterCritical() ;
	if(OSMsgQArea[eID].count != 0)
	{
		tmp = 1 ;
		*msg = OSMsgQArea[eID].buf[OSMsgQArea[eID].front] ;
	}
	OSExitCritical() ;
	return tmp ;
}

/************************************************************************************************
* 发送消息到消息队列 公共代码 不含临界保护 不能直接调有 
* 参数：eID 消息队列ID  msg 消息
*************************************************************************************************/
void OSSignalMsgQ(OStypeInt8u eID,OStypeInt8u msg) 
{
	OStypeInt8u tmp ;

	if(OSMsgQArea[eID].count < OSMsgQArea[eID].size)
	{
		OSMsgQArea[eID].buf[OSMsgQArea[eID].rear] = msg ;
		if(++OSMsgQArea[eID].rear == OSMsgQArea[eID].size) OSMsgQArea[eID].rear = 0 ;
		OSMsgQArea[eID].count++ ;
		if(OSHeadMsgQ(eID) != OSListArea[OSHeadMsgQ(eID)].next)
		{
			tmp = OSHiPrioInList(OSHeadMsgQ(eID)) ;
			OSTcbArea[tmp].state = OSTCB_ELIGIBLE ;
#if OSBYTES_OF_DELAYS > 0
			OSTcbArea[tmp].delay = 0 ;
#endif
//			SP++ ;
//			*(OStypeInt8u idata *)SP = tmp ;
			OSDelFromList(tmp) ;
//			tmp = *(OStypeInt8u idata *)SP ;
//			SP-- ;
			OSAppendToList(OSHeadEligible,tmp) ;
		}
	}
	return ;
}

/************************************************************************************************
* 在任务中发送消息到消息队列  
* 参数：eID  消息队列ID  msg 消息
* 返加：0-操作失败 1-操作成功
*************************************************************************************************/
void OSTaskSignalMsgQ(OStypeInt8u eID,OStypeInt8u msg) 
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSMSGQS-1) return ;
#endif
	OSEnterCritical() ;
	OSSignalMsgQ(eID,msg) ;
#if OSMETHOD > 0
	OSTaskSw() ;
#endif
	OSExitCritical() ;
	return ;
}

/************************************************************************************************
* 在中断中发送消息到消息队列  
* 参数：eID 消息队列ID  msg 消息
* 返加：0-操作失败 1-操作成功
************************************************************************************************/
void OSIntSignalMsgQ(OStypeInt8u eID,OStypeInt8u msg) 
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSMSGQS-1) return ;
#endif
	OSEnterCritical() ;
	OSSignalMsgQ(eID,msg) ;
#if OSMETHOD > 0
	OSPendSVAct() ;
#endif
	OSExitCritical() ;
	return ;
}

/************************************************************************************************
* 返回队列消息个数  
* 参数：eID  消息队列ID 
* 返加：消息个数 
*************************************************************************************************/
OStypeInt8u OSMsgQCount(OStypeInt8u eID) 
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSMSGQS-1) return 0;
#endif
	return OSMsgQArea[eID].count ;
}

/************************************************************************************************
* 返回队列可用空间  
* 参数：eID  消息队列ID 
* 返加：可用空间个数 
*************************************************************************************************/
OStypeInt8u OSMsgQEmpty(OStypeInt8u eID) 
{
	OStypeInt8u tmp ;
	
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSMSGQS-1) return 0;
#endif
	OSEnterCritical() ;
	tmp = OSMsgQArea[eID].size - OSMsgQArea[eID].count ;
	OSExitCritical() ;
	return tmp ;
}

#endif

